// Ninf-G-XX, ver. 0.1
// Copyright 2011 National Institute of Advanced Industrial Science and Technology
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cerrno>
#include <string>
#include <cstring>
#include <errno.h>

#include "FpInputStream.hpp"
#include "Exception.hpp"

using namespace std;
using namespace ninf::lib;
  /* constructor */
FpInputStream :: FpInputStream(FILE * fp): fp(fp), closed(false){}

FpInputStream :: FpInputStream(const char * filename): closed(false){
		init(filename);
}

FpInputStream :: FpInputStream(const std::string & filename): closed(false){
		init(filename.c_str());
}

FpInputStream :: ~FpInputStream(){
  if (!closed)
    fclose(fp);
}

void
FpInputStream :: init(const char * filename) {
  fp = fopen(filename, "r");
  if (fp == NULL){
    string tmp("cannot open file '");
    tmp += filename;
    tmp += "'";
    EXCEPTION(tmp);
  }
}

/**
 * read a single byte 
 * if it encounters EOF returns -1
 * if it encounters some error throws exception
 */
int 
FpInputStream :: read(){
  unsigned char temp[1];

  int ret = fread(temp, 1, 1, fp);
  if (ret < 0){
    if (feof(fp))
      return -1; // EOF
    else {
      const char * tmp = strerror(errno);
      EXCEPTION(tmp);
    }      
  }

  if (ret == 0)
    EXCEPTION("fread returned zero");    

  return ret;
}

/*
 * read byte array and stores it to val 
 * it returns number of actually read bytes
 */ 
int
FpInputStream :: read(char * val, int offset, int len){
  int ret = fread(val + offset, 1, len, fp);
  if (ret < 0){
    if (feof(fp))
      return -1; // EOF
    else {
      const char * tmp = strerror(errno);
      EXCEPTION(tmp);
    }      
  }
  if (ret == 0)
    EXCEPTION("fread returned zero");    

  return ret;
}


  /*
   * read byte array and stores it to val 
   * keep tring to read specified length
   * returns non 0 if succuess, 0 if failed
   */ 
int
FpInputStream :: readFully(char * val, int offset, int len){
  int readed = 0;

  while (len > readed){
    int ret = fread(val + offset + readed, 1, len - readed, fp);
    if (ret < 0){
      if (feof(fp))
	return -1; // EOF
      else {
	const char * tmp = strerror(errno);
	EXCEPTION(tmp);
      }      
    }
    if (ret == 0)
      EXCEPTION("fread returned zero");    

    readed += ret;
  }
  return 1;
}

  /*
   * close underlying stream
   */ 
void 
FpInputStream :: close(){
  if (!closed)
    fclose(fp);
  closed = true;
}
